package com.qf;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * 分布式锁模拟实现
 */
@SpringBootTest
public class App1 {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void test2(){
        Boolean tickets = redisTemplate.opsForValue().setIfAbsent("tickets", 1);
        Boolean tickets2 = redisTemplate.opsForValue().setIfAbsent("tickets", 1);

        System.out.println(tickets);
        System.out.println(tickets2);
    }

    @Test
    public void test1() throws IOException {
        new Thread(()->{
            while (true) {
                //如果多个应用之间，要想使用锁锁住代码，原本的synchronized/Lock做不到了。此时我们只能使用分布式锁
                //这个方法内部使用的是setnx，如果这个键存在， 设置失败，如果这个键不存在，设置成功    synchronized 可重入锁

                //加锁
                redisTemplate.opsForValue().get("tickets");
                Boolean tickets = redisTemplate.opsForValue().setIfAbsent("tickets", 1,2, TimeUnit.SECONDS);

               /* //看门狗 -- 给锁续时 （这里因为键会被序列化， 所以这个键不对，此处模拟看门狗程序对锁续时）
                Thread thread = new Thread(()->{
                    //给这个锁续时
                    while (true) {
                        Long tickets1 = redisTemplate.getExpire("tickets");
                        if (tickets1 < 1) {
                            redisTemplate.expire("tickets1", 2, TimeUnit.SECONDS);
                        }
                    }
                });
                thread.setDaemon(true);
                thread.start();*/

                if (tickets) {
                    if (Num.tickets > 0) {
                        //卖票
                        System.out.println("窗口1，正在卖第"+Num.tickets+"张票");
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        Num.tickets--;

                        //异常
                        int i= 1/0;

                        System.out.println("窗口1，剩余票数：" + Num.tickets);
                    }

                    //释放锁
                    redisTemplate.delete("tickets");
                }
            }
        }).start();


        new Thread(()->{
            while (true) {
                //加锁
                redisTemplate.opsForValue().get("tickets");
                Boolean tickets = redisTemplate.opsForValue().setIfAbsent("tickets", 1,2,TimeUnit.SECONDS);
                if (tickets) {
                    if (Num.tickets > 0) {
                        //卖票
                        System.out.println("窗口2，正在卖第"+Num.tickets+"张票");
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        Num.tickets--;

                        System.out.println("窗口2，剩余票数：" + Num.tickets);
                    }
                    //释放锁
                    redisTemplate.delete("tickets");
                }
            }
        }).start();



        System.in.read();
    }
}
